package com.enjoyor.soa.traffic.server.tsms.handler;

import com.enjoyor.soa.traffic.core.tsms.domain.MsgInfo;
import com.enjoyor.soa.traffic.core.tsms.domain.RouteInfo;
import com.enjoyor.soa.traffic.core.tsms.domain.RoutePoint;
import com.enjoyor.soa.traffic.core.tsms.domain.TaskExecuteRecord;
import com.enjoyor.soa.traffic.core.tsms.enums.EnumDicPublic;
import com.enjoyor.soa.traffic.server.tsms.common.RehearseGlobal;
import com.enjoyor.soa.traffic.server.tsms.dubbo.impl.DubboSchemeActionService;
import com.enjoyor.soa.traffic.util.handler.BasicMsgHandler;
import com.enjoyor.soa.traffic.util.helper.GeoToolsHelper;
import com.enjoyor.soa.traffic.util.helper.LoggerHelper;
import com.enjoyor.soa.traffic.util.helper.TimeHelper;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 接收数据，数据清理
 */
public class MapingHandler extends BasicMsgHandler<MsgInfo> {
    private MapingHandler() {
        super(1000, "坐标映射与推送");
    }

    private static MapingHandler single;

    public static MapingHandler getInstance() {
        if (single == null) {
            synchronized (MapingHandler.class) {
                if (single == null) {
                    single = new MapingHandler();
                    //最少5个线程 最多加到5个线程，积压20个累加
                    single.setMultiProcess(5, 20, 20);
                    single.addNextHandler(AlarmDistanceHandler.getInstance());//位置过近报警
                    single.addNextHandler(CameraControlHandler.getInstance());//视频控制及抢占报警
                    single.addNextHandler(TrafficSignalControlHandler.getInstance());//信号机相关的控制及报警
                    //single.addNextHandler(ClashPrognosisHandler.getInstance());//冲突预判
                    single.addNextHandler(AlarmDataDelayHandler.getInstance());//冲突预判

                }
            }
        }
        return single;
    }

    long lasttime = 0l;

    @Override
    protected boolean task(int taskTimes) {
        com.alibaba.fastjson.JSONObject jsonObject2 = new com.alibaba.fastjson.JSONObject();
        if (taskTimes > 5) {
            for (String key : RehearseGlobal.ActionDataPool.keySet()) {
                Map<String, Object> lastGeo = (Map<String, Object>) RehearseGlobal.ActionDataPool.get(key).get("lastGeo");
                if (lastGeo != null) {
                    long lastLong = ((Date) lastGeo.get("receiveTime")).getTime();
                    long thisLong = new Date().getTime();
                    long slottime = (thisLong - lastLong) / 1000 / 60; //最新定位时间与当前时间 差转为分
                    //超过五分钟或十分钟没有定位数据进行报警
                    int positionWranNum = Integer.parseInt(RehearseGlobal.ActionDataPool.get(key).get("positionWranNum").toString());
                    if ((slottime > DubboSchemeActionService.nocoordTime && positionWranNum == 0) || (slottime > DubboSchemeActionService.nocoordTime * 2
                            && positionWranNum == 1)) {
                        Map<String, Object> positionWranMap = new HashMap();
                        String content = RehearseGlobal.ActionDataPool.get(key).get("taskName") + ":定位设备" 
                        		+ RehearseGlobal.ActionDataPool.get(key).get("positionDeviceId") + "已超过" + slottime + "分钟未收到定位数据！";
                        positionWranMap.put("type", "warn");
                        positionWranMap.put("recordTime", TimeHelper.dateToLongString());
                        positionWranMap.put("clash", content);
                        positionWranMap.put("content", content);
                        jsonObject2.put(RehearseGlobal.ActionDataPool.get(key).get("routeId").toString(), positionWranMap);
                        InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + key, jsonObject2);
                        positionWranNum++;
                        RehearseGlobal.ActionDataPool.get(key).put("positionWranNum", positionWranNum);
                        //记录开始执行信息
                        TaskExecuteRecord taskExecuteRecord = new TaskExecuteRecord();
                        taskExecuteRecord.setExecuteTaskId(key);
                        taskExecuteRecord.setIsWarn("1");
                        taskExecuteRecord.setRecordTypeId(EnumDicPublic.WRAN_POSITION_OFF.getKey());
                        taskExecuteRecord.setRecordTypeName(EnumDicPublic.WRAN_POSITION_OFF.getValue());
                        taskExecuteRecord.setRecordContent(content);
                        InitializeHandler.getInstance().getTaskExecuteRecordService().insertRecord(taskExecuteRecord, "执行报警");
                    }
                }
            }
            return true;
        } else {
            return false;
        }

    }

    @Override
    protected boolean process(MsgInfo msg) {

        com.alibaba.fastjson.JSONObject jsonObject2 = new com.alibaba.fastjson.JSONObject();
        String executeTaskId = msg.getExecuteTaskId();
        if (RehearseGlobal.ActionDataPool.get(executeTaskId) != null && !(boolean) RehearseGlobal.ActionDataPool.get(executeTaskId).get("stop")) {
            String routeId = RehearseGlobal.ActionDataPool.get(executeTaskId).get("routeId").toString();
            GeoToolsHelper geoToolsHelper = new GeoToolsHelper();
            Map<String, Object> map2 = new HashMap();
            Map<String, Object> lastGeo = (Map<String, Object>) RehearseGlobal.ActionDataPool.get(executeTaskId).get("lastGeo");
            Map<String, Object> lastDeviateGeo = (Map<String, Object>) RehearseGlobal.ActionDataPool.get(executeTaskId).get("lastDeviateGeo");
            List<RouteInfo> routeInfoList = (List<RouteInfo>) RehearseGlobal.ActionDataPool.get(executeTaskId).get("routeInfoList");
            if (lastGeo.isEmpty()) {
                //第一次收到坐标
                map2 = geoToolsHelper.getProjectionPoint(routeInfoList.get(0).getRouteGeo(), msg.getLongitude(), msg.getLatitude());
                //System.out.println(map2.get("shortestDis").toString());
                if (Double.parseDouble(map2.get("shortestDis").toString()) < DubboSchemeActionService.deviateLength) {
                    lastGeo.put("realX", msg.getLongitude());
                    lastGeo.put("realY", msg.getLatitude());
                    lastGeo.put("x", map2.get("x"));//映射点坐标
                    lastGeo.put("y", map2.get("y"));
                    lastGeo.put("updateTime", msg.getUpdateTime());//上次定位数据更新时间
                    lastGeo.put("receiveTime", msg.getReceiveTime());//上次定位数据接受时间
                    lastGeo.put("useTime", msg.getReceiveTime());//上次有效定位数据更新时间
                    lastGeo.put("distanceStartPointLength", (double) map2.get("distanceStartPointLength"));//上次有效映射点距起点距离
                    lastGeo.put("deviateTimeNum", 0);//计划时间偏离计数
                    lastGeo.put("deviateCoordNum", 0);//线路偏离计数
                    lastGeo.put("shortestDis", (double) map2.get("shortestDis"));
                } else {
                    Map<String, Object> routemap = new HashMap();
                    routemap.put("type", "point");
                    routemap.put("isDeviateCoord", true);//坐标偏离是否产生报警
                    routemap.put("mapLength", 0);//已行驶距离
                    routemap.put("speed", msg.getSpeed());//行驶速度
                    routemap.put("realX", msg.getLongitude());//实际定位坐标
                    routemap.put("realY", msg.getLatitude());
                    routemap.put("x", 0);//映射点坐标
                    routemap.put("y", 0);
                    routemap.put("percent", 0);
                    jsonObject2.put(routeId, routemap);
                    InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + executeTaskId, jsonObject2);
                    return true;
                }
            } else {
                lastGeo.put("receiveTime", msg.getReceiveTime());
                //非第一次收到坐标
                long thisLong = msg.getReceiveTime().getTime();
                if (!(boolean) RehearseGlobal.ActionDataPool.get(executeTaskId).get("isDeviateCoord")) {
                    //之前没报警
                    //如果没有线路偏移报警,按照lastGeo记录定位计算
                    long useLong = ((Date) lastGeo.get("useTime")).getTime();
                    double lastLength = (double) lastGeo.get("distanceStartPointLength");
                    //预计最多行驶距离（暂时按100km/h计算）
                    double goLength = (thisLong - useLong) * DubboSchemeActionService.maxSpeed * 1000 / 3600 / 1000;
                    //System.out.println("收到坐标"+geo[0]+"_"+geo[1] + "_"+routeInfoList.get(0).getRouteGeo());
                    List<Map> mapList = geoToolsHelper.getProjectionPointList(routeInfoList.get(0).getRouteGeo(), msg.getLongitude(), msg.getLatitude());


                    for (int m = 0; m < mapList.size(); m++) {
                        double startPointLength = (double) mapList.get(m).get("distanceStartPointLength");
                        //System.out.println("ddddddd"+startPointLength+"---"+lastLength+"======" + goLength);
                        if (startPointLength >= lastLength && startPointLength <= lastLength + goLength) {
                            map2 = mapList.get(m);
                            break;
                        }
                    }
                    //没有找到符合要求的映射点或者定位偏离200m以外，
                    if (map2.isEmpty() || (double) map2.get("shortestDis") > DubboSchemeActionService.deviateLength) {
                        //LoggerHelper.LOG.error("偏移数据------------上一个点距离起点：" + lastLength + "；当前最多可到达" + (lastLength + goLength));
                        //LoggerHelper.LOG.error(mapList);
                        lastGeo.put("deviateCoordNum", (int) lastGeo.get("deviateCoordNum") + 1);
                    } else {
                        //mapLength = (double) map2.get("distanceStartPointLength");
                        lastGeo.put("realX", msg.getLongitude());//实际坐标
                        lastGeo.put("realY", msg.getLatitude());
                        lastGeo.put("x", map2.get("x"));//映射点坐标
                        lastGeo.put("y", map2.get("y"));
                        lastGeo.put("useTime", msg.getReceiveTime());
                        lastGeo.put("distanceStartPointLength", (double) map2.get("distanceStartPointLength"));
                        lastGeo.put("deviateCoordNum", 0);
                        lastGeo.put("shortestDis", (double) map2.get("shortestDis"));
                    }
                    //定位偏离线路连续大于10次报警
                    if (lastGeo.containsKey("deviateCoordNum") && (int) lastGeo.get("deviateCoordNum") > DubboSchemeActionService.deviateTimes
                            && !(boolean) RehearseGlobal.ActionDataPool.get(executeTaskId).get("isDeviateCoord")) {
                        RehearseGlobal.ActionDataPool.get(executeTaskId).put("isDeviateCoord", true);
                        //lastGeo.put("deviateCoordNum", 0);
                        Map<String, Object> coordWranMap = new HashMap();
                        String content = RehearseGlobal.ActionDataPool.get(executeTaskId).get("taskName") + ":前导车已偏离制定的线路!";
                        coordWranMap.put("type", "warn");
                        coordWranMap.put("recordTime", TimeHelper.dateToLongString());
                        coordWranMap.put("content", content);
                        coordWranMap.put("clash", content);
                        jsonObject2.put(routeId, coordWranMap);
                        InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + executeTaskId, jsonObject2);

                        //记录开始执行信息
                        TaskExecuteRecord taskExecuteRecord = new TaskExecuteRecord();
                        taskExecuteRecord.setExecuteTaskId(executeTaskId);
                        taskExecuteRecord.setIsWarn("1");
                        taskExecuteRecord.setRecordTypeId(EnumDicPublic.WRAN_ROUTE_DEVIATE.getKey());
                        taskExecuteRecord.setRecordTypeName(EnumDicPublic.WRAN_ROUTE_DEVIATE.getValue());
                        taskExecuteRecord.setRecordContent(content);
                        InitializeHandler.getInstance().getTaskExecuteRecordService().insertRecord(taskExecuteRecord, "执行报警");
                    }
                } else {
                    //之前就再报警中
                    if (lastDeviateGeo.isEmpty() || (lastDeviateGeo.containsKey("normalCoordNum") && (int) lastDeviateGeo.get("normalCoordNum") == 0)) {
                        lastDeviateGeo.put("realX", lastGeo.get("realX"));//实际坐标
                        lastDeviateGeo.put("realY", lastGeo.get("realY"));
                        lastDeviateGeo.put("x", lastGeo.get("x"));//映射点坐标
                        lastDeviateGeo.put("y", lastGeo.get("y"));
                        lastDeviateGeo.put("useTime", lastGeo.get("useTime"));
                        lastDeviateGeo.put("distanceStartPointLength", lastGeo.get("distanceStartPointLength"));
                        lastDeviateGeo.put("normalCoordNum", 0);
                    }
                    //如果发生线路偏移报警,按照lastDeviateGeo记录定位计算
                    long useLong = ((Date) lastDeviateGeo.get("useTime")).getTime();
                    double lastLength = (double) lastDeviateGeo.get("distanceStartPointLength");
                    //预计最多行驶距离（暂时按100km/h计算）
                    double goLength = (thisLong - useLong) * DubboSchemeActionService.maxSpeed * 1000 / 3600 / 1000;
                    //System.out.println("收到坐标"+geo[0]+"_"+geo[1] + "_"+routeInfoList.get(0).getRouteGeo());
                    List<Map> mapList = geoToolsHelper.getProjectionPointList(routeInfoList.get(0).getRouteGeo(), msg.getLongitude(), msg.getLatitude());
                    for (int m = 0; m < mapList.size(); m++) {
                        double startPointLength = (double) mapList.get(m).get("distanceStartPointLength");
                        if (startPointLength >= lastLength && startPointLength <= lastLength + goLength) {
                            map2 = mapList.get(m);
                            break;
                        }
                    }
                    //没有找到符合要求的映射点或者定位偏离200m以外，
                    if (map2.isEmpty() || (double) map2.get("shortestDis") > DubboSchemeActionService.deviateLength) {
                        lastDeviateGeo.put("normalCoordNum", 0);
                    } else {
                        //LoggerHelper.LOG.error("正常数据*************88上一个点距离起点：" + lastLength + "；当前最多可到达" + (lastLength + goLength));
                        //LoggerHelper.LOG.error(mapList);
                        //mapLength = (double) map2.get("distanceStartPointLength");
                        lastDeviateGeo.put("realX", msg.getLongitude());//实际坐标
                        lastDeviateGeo.put("realY", msg.getLatitude());
                        lastDeviateGeo.put("x", map2.get("x"));//映射点坐标
                        lastDeviateGeo.put("y", map2.get("y"));
                        lastDeviateGeo.put("useTime", msg.getReceiveTime());
                        lastDeviateGeo.put("distanceStartPointLength", (double) map2.get("distanceStartPointLength"));
                        lastDeviateGeo.put("normalCoordNum", (int) lastDeviateGeo.get("normalCoordNum") + 1);
                    }
                    //连续10次获取正常映射点，提示自动回归正常线路
                    if (lastDeviateGeo.containsKey("normalCoordNum") && (int) lastDeviateGeo.get("normalCoordNum") > DubboSchemeActionService.normalTimes
                            && (boolean) RehearseGlobal.ActionDataPool.get(executeTaskId).get("isDeviateCoord")) {
                        RehearseGlobal.ActionDataPool.get(executeTaskId).put("isDeviateCoord", false);
                        lastDeviateGeo.put("normalCoordNum", 0);
                        Map<String, Object> coordWranMap = new HashMap();
                        String content = RehearseGlobal.ActionDataPool.get(executeTaskId).get("taskName")+":前导车已自动回归原制定线路!";
                        coordWranMap.put("type", "info");
                        coordWranMap.put("recordTime", TimeHelper.dateToLongString());
                        coordWranMap.put("clash", content);
                        coordWranMap.put("content", content);
                        jsonObject2.put(routeId, coordWranMap);
                        InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + executeTaskId, jsonObject2);

                        //记录开始执行信息
                        TaskExecuteRecord taskExecuteRecord = new TaskExecuteRecord();
                        taskExecuteRecord.setExecuteTaskId(executeTaskId);
                        taskExecuteRecord.setIsWarn("0");
                        taskExecuteRecord.setRecordTypeId(EnumDicPublic.INFO_ROUTE_RECOVER.getKey());
                        taskExecuteRecord.setRecordTypeName(EnumDicPublic.INFO_ROUTE_RECOVER.getValue());
                        taskExecuteRecord.setRecordContent(content);
                        InitializeHandler.getInstance().getTaskExecuteRecordService().insertRecord(taskExecuteRecord, "执行信息");
                    }
                }
            }
            Map<String, Object> routemap = new HashMap<String, Object>();
            double mapLength = (double) lastGeo.get("distanceStartPointLength");
            List<RoutePoint> routePointList = (List<RoutePoint>) RehearseGlobal.ActionDataPool.get(executeTaskId).get("routePointList");
            int iPoint = 0;
            for (int i = 1; i < routePointList.size(); i++) {
                if (mapLength < routePointList.get(i).getPointLength()) {
                    if (RehearseGlobal.ActionDataPool.get(msg.getExecuteTaskId()).get("iPoint") != null) {
                        iPoint = Integer.parseInt(RehearseGlobal.ActionDataPool.get(msg.getExecuteTaskId()).get("iPoint").toString());
                        if (iPoint + 1 != i) {
                            break;
                        }
                    }
                    iPoint = i;
                    RehearseGlobal.ActionDataPool.get(msg.getExecuteTaskId()).put("iPoint", i);
                    System.out.println("经过途经点" + routePointList.get(i - 1).getPointName());
                    ClashPrognosisHandler.getInstance().handle(msg.getExecuteTaskId());//预测线路冲突情况
                    
                    try {
                    	double lastPointlength = mapLength - routePointList.get(i-1).getPointLength();//距上个途径点长度
                        double planSpeed = routePointList.get(i).getSpeed();
                        double planUseTime = lastPointlength * 3600/(planSpeed*1000);//从上个途径点到当前位置预计使用时间（单位s）
                        //上个途径点计划出发时间
                        String lastPointTime = TimeHelper.dateToShortString(new Date()) + " " + routePointList.get(i-1).getPlanTime() + ":00";
						long lastPointTimeL = TimeHelper.StringToDateTime(lastPointTime, "yyyy-MM-dd HH:mm:ss");//转换时间戳
	                    long nowTimeL = new Date().getTime();
	                    long betweenTime = (nowTimeL - lastPointTimeL - (long)planUseTime*1000)/60/1000;//实际与计划相差时间（单位：分）
	                    boolean warnFlag = false;
	                    String content = "";
	                    if(betweenTime > 5) {
	                    	warnFlag = true;
	                    	content = RehearseGlobal.ActionDataPool.get(executeTaskId).get("taskName") + ":比预计时间慢了"+betweenTime+"分钟，请加速！";
	                    }else if(betweenTime < -5) {
	                    	warnFlag = true;
	                    	content = RehearseGlobal.ActionDataPool.get(executeTaskId).get("taskName") + ":比预计时间快了"+(-betweenTime)+"分钟，请减速！";
	                    }
	                    if(warnFlag) {
	                    	Map<String, Object> timeWranMap = new HashMap<String, Object>();
	                    	timeWranMap.put("type", "warn");
	                    	timeWranMap.put("recordTime", TimeHelper.dateToLongString());
	                    	timeWranMap.put("content", content);
	                    	timeWranMap.put("clash", content);
	                        jsonObject2.put(routeId, timeWranMap);
	                        InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + executeTaskId, jsonObject2);
	                        //记录时间偏离报警信息
	                        TaskExecuteRecord taskExecuteRecord = new TaskExecuteRecord();
	                        taskExecuteRecord.setExecuteTaskId(executeTaskId);
	                        taskExecuteRecord.setIsWarn("1");
	                        taskExecuteRecord.setRecordTypeId(EnumDicPublic.WRAN_TIME_DEVIATE.getKey());
	                        taskExecuteRecord.setRecordTypeName(EnumDicPublic.WRAN_TIME_DEVIATE.getValue());
	                        taskExecuteRecord.setRecordContent(content);
	                        InitializeHandler.getInstance().getTaskExecuteRecordService().insertRecord(taskExecuteRecord, "执行报警");
	                    }
					} catch (ParseException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
                    
                    break;
                }
            }
            routemap.put("type", "point");
            routemap.put("isDeviateCoord", RehearseGlobal.ActionDataPool.get(executeTaskId).get("isDeviateCoord"));//坐标偏离是否产生报警
            routemap.put("mapLength", mapLength);//已行驶距离
            routemap.put("speed", msg.getSpeed());//行驶速度
            routemap.put("realX", msg.getLongitude());//实际定位坐标
            routemap.put("realY", msg.getLatitude());
            routemap.put("x", map2.get("x"));//映射点坐标
            routemap.put("y", map2.get("y"));
            routemap.put("shortestDis", (double) lastGeo.get("shortestDis"));//实际坐标与映射坐标的距离
            routemap.put("arrivedPointIdx", iPoint - 1);//上个途径点序号
            routemap.put("restlength", routePointList.get(iPoint).getPointLength() - mapLength);//距下个途径点长度
            routemap.put("pointId", routePointList.get(iPoint).getPointId());//下个途径点编号
            //routemap.put("percent", (mapLength - routePointList.get(iPoint - 1).getPointLength()) / (routePointList.get(iPoint).getPointLength() - routePointList.get(iPoint - 1).getPointLength()));
            routemap.put("percent", mapLength/routePointList.get(routePointList.size()-1).getPointLength());
            jsonObject2.put(routeId, routemap);
            InitializeHandler.getInstance().getServerPushServiceImpl().pushMessage("" + executeTaskId, jsonObject2);
            System.out.println(map2.get("x") + "-------" + map2.get("y"));
            if (!(boolean) RehearseGlobal.ActionDataPool.get(executeTaskId).get("isDeviateCoord")) {
                if (map2.get("x") != null && map2.get("x") != null) {
                    msg.setX(Double.parseDouble(map2.get("x").toString()));
                    msg.setY(Double.parseDouble(map2.get("y").toString()));
                }
            }
            return true;
        }
        return false;
    }
}
